#include <stdlib.h>
#include <iostream>

#include "framebuffer.h"

Framebuffer::Framebuffer (GLenum target) {
    
    this->target = target;
    
    this->generate();
    this->bind();
    
    glReadBuffer(GL_NONE);
    glDrawBuffer(GL_NONE);
    
}

Framebuffer::Framebuffer (GLenum target, GLuint framebuffer) {
    this->target = target;
    this->id = framebuffer;
    
    this->bind();
}

Framebuffer::~Framebuffer () {
    unsigned int size = this->texturesResize.size();
    
    for (unsigned int i=0; i<size; i++) {
         delete this->texturesResize.at(i);
    }
}

GLuint Framebuffer::getID () {
    return this->id;
}

void Framebuffer::generate () {
    glGenFramebuffers(1, &this->id);
}

void Framebuffer::bind () {
    glBindFramebuffer(this->target, this->id);
}    

void Framebuffer::addTexture2D (GLenum attachment, Texture *texture) {
    // this texture must be resized when window is resized
    this->texturesResize.push_back(texture);
    
    glFramebufferTexture2D(this->target, attachment, GL_TEXTURE_2D, texture->getID(), 0);
    this->attachments.push_back(attachment);
}

void Framebuffer::addTexture2D (GLenum attachment, Texture *texture, GLenum unit) {
    FramebufferTexture framebufferTexture;
    framebufferTexture.texture = texture;
    framebufferTexture.unit = unit;
    
    this->textures.push_back(framebufferTexture);
    
    this->addTexture2D (attachment, texture);
}

void Framebuffer::drawBuffers() {
    unsigned int size = this->attachments.size();
    GLsizei count = 0;
    
    if (size > 0) {
        
        GLenum *buffers = (GLenum *) malloc(sizeof(GLenum)*size);
        
        if (buffers != NULL) {
            for(unsigned int i=0; i<size; i++) {
                
                GLenum attachment = this->attachments.at(i);
                
                if (attachment != GL_DEPTH_ATTACHMENT) {
                    buffers[i] = attachment;
                    count++;
                }
            }
            
            glDrawBuffers(count, buffers);
            
            free(buffers);
        } else {
            cerr << "Framebuffer drawBuffers: allocation failed" << endl;
        }
        
    }
}

void Framebuffer::bindTextures () {
    unsigned int size = this->textures.size();
    
    for (unsigned int i=0; i<size; i++) {        
        FramebufferTexture framebufferTexture = this->textures.at(i);
        framebufferTexture.texture->bind(framebufferTexture.unit);
    }
}

void Framebuffer::resizeTextures (int width, int height) {
    unsigned int size = this->texturesResize.size();
    
    for (unsigned int i=0; i<size; i++) {
         this->texturesResize.at(i)->setSize(width, height);
    }
}

